/**
 * edurender
 * Quake3Model.cpp
 * (c) 2009 J. Brad Byrd
 */

#include "Quake3Model.h"

#include <string>
#include <cstdio>

const float er::Quake3ModelReader::MD3_XYZ_SCALE = 1.0f / 64.0f;

er::Quake3ModelReader *er::Quake3ModelReader::Create(const char *fileName)
{
	Quake3ModelReader *model = new Quake3ModelReader();
	
	if (!model->Read(fileName))
	{
		delete model;
		return 0;
	}

	return model;
}

void er::Quake3ModelReader::Destroy(er::Quake3ModelReader *model)
{
	delete model;
}

er::Quake3ModelReader::Quake3ModelReader()
{	
}

bool er::Quake3ModelReader::Read(const char *fileName)
{
	FILE *fp = std::fopen(fileName, "rb");
	
	if (fp == NULL)
		return false;	

	char ident[4];
	std::fread(&ident, 1, 4, fp);
	
	if ( !(ident[0] == 'I'
		&& ident[1] == 'D'
		&& ident[2] == 'P'
		&& ident[3] == '3'))
		goto error;

	__int32 version;
	std::fread(&version, sizeof(__int32), 1, fp);
	
	char name[MAX_QPATH];
	std::fread(name, 1, MAX_QPATH, fp);
	
	__int32 flags;
	std::fread(&flags, sizeof(__int32), 1, fp);

	__int32 numFrames;
	__int32 numTags;
	__int32 numSurfaces;
	__int32 numSkins;
	
	std::fread(&numFrames, sizeof(__int32), 1, fp);
	std::fread(&numTags, sizeof(__int32), 1, fp);
	std::fread(&numSurfaces, sizeof(__int32), 1, fp);
	std::fread(&numSkins, sizeof(__int32), 1, fp);
	
	__int32 ofsFrames;
	__int32 ofsTags;
	__int32 ofsSurfaces;
	
	std::fread(&ofsFrames, sizeof(__int32), 1, fp);
	std::fread(&ofsTags, sizeof(__int32), 1, fp);
	std::fread(&ofsSurfaces, sizeof(__int32), 1, fp);

	std::fseek(fp, ofsFrames, SEEK_SET);
	m_frames.resize(numFrames);
	
	for (size_t i = 0; i < m_frames.size(); ++i)
		m_frames[i].Read(fp);	
	
	std::fseek(fp, ofsTags, SEEK_SET);
	m_tags.resize(numTags);

	for (size_t i = 0; i < m_tags.size(); ++i)
		m_tags[i].Read(fp);
	
	std::fseek(fp, ofsSurfaces, SEEK_SET);
	m_surfaces.resize(numSurfaces);
	
	for (size_t i = 0; i < m_surfaces.size(); ++i)
		m_surfaces[i].Read(fp);

	std::fclose(fp);
	
	return true;

error:
	std::fclose(fp);
	return false;
}

void er::Quake3ModelReader::Frame::Read(FILE *fp)
{		
	std::fread(&m_minBounds.x, sizeof(float), 1, fp);
	std::fread(&m_minBounds.y, sizeof(float), 1, fp);
	std::fread(&m_minBounds.z, sizeof(float), 1, fp);

	std::fread(&m_maxBounds.x, sizeof(float), 1, fp);
	std::fread(&m_maxBounds.y, sizeof(float), 1, fp);
	std::fread(&m_maxBounds.z, sizeof(float), 1, fp);
	
	std::fread(&m_localOrigin.x, sizeof(float), 1, fp);
	std::fread(&m_localOrigin.y, sizeof(float), 1, fp);
	std::fread(&m_localOrigin.z, sizeof(float), 1, fp);
	
	std::fread(&m_radius, sizeof(float), 1, fp);
	
	std::fread(m_name, sizeof(char), 16, fp);
}

void er::Quake3ModelReader::Tag::Read(FILE *fp)
{
	std::fread(&m_name, sizeof(char), MAX_QPATH, fp);
	
	std::fread(&m_origin.x, sizeof(float), 1, fp);
	std::fread(&m_origin.y, sizeof(float), 1, fp);
	std::fread(&m_origin.z, sizeof(float), 1, fp);
	
	for (int j = 0; j < 3; ++j)
	{
		std::fread(&m_axis[j].x, sizeof(float), 1, fp);
		std::fread(&m_axis[j].y, sizeof(float), 1, fp);
		std::fread(&m_axis[j].z, sizeof(float), 1, fp);
	}
}

void er::Quake3ModelReader::Surface::Read(FILE *fp)
{
	long surfaceStart = std::ftell(fp);

	__int32 ident;
	std::fread(&ident, sizeof(__int32), 1, fp);
	
	char name[MAX_QPATH];
	std::fread(name, sizeof(char), MAX_QPATH, fp);
	
	__int32 flags;
	std::fread(&flags, sizeof(__int32), 1, fp);
	
	__int32 numShaders;
	__int32 numTriangles;
	std::fread(&m_frameCount, sizeof(unsigned __int32), 1, fp);
	std::fread(&numShaders, sizeof(__int32), 1, fp);
	std::fread(&m_vertCount, sizeof(unsigned __int32), 1, fp);
	std::fread(&numTriangles, sizeof(__int32), 1, fp);
	
	__int32 ofsTriangles;
	__int32 ofsShaders;
	__int32 ofsSt;
	__int32 ofsXyzNormal;
	__int32 ofsEnd;
	std::fread(&ofsTriangles, sizeof(__int32), 1, fp);		
	std::fread(&ofsShaders, sizeof(__int32), 1, fp);		
	std::fread(&ofsSt, sizeof(__int32), 1, fp);		
	std::fread(&ofsXyzNormal, sizeof(__int32), 1, fp);		
	std::fread(&ofsEnd, sizeof(__int32), 1, fp);
	
	std::fseek(fp, surfaceStart, SEEK_SET);
	std::fseek(fp, ofsTriangles, SEEK_CUR);
	
	m_indices.resize(numTriangles * 3);
	
	for (__int32 i = 0; i < numTriangles * 3; ++i)
	{
		std::fread(&m_indices[i], sizeof(__int32), 1, fp);
	}
	
	std::fseek(fp, surfaceStart, SEEK_SET);
	std::fseek(fp, ofsXyzNormal, SEEK_CUR);
			
	m_xyzNormals.resize(m_vertCount);
	
	for (unsigned __int32 i = 0; i < m_vertCount; ++i)
	{
		XyzNormal *vertex = &m_xyzNormals[i];
		
		std::fread(&vertex->x, sizeof(__int16), 1, fp);
		std::fread(&vertex->y, sizeof(__int16), 1, fp);
		std::fread(&vertex->z, sizeof(__int16), 1, fp);

		std::fread(&vertex->normal, sizeof(__int16), 1, fp);
	}
	
	std::fseek(fp, surfaceStart, SEEK_SET);
	std::fseek(fp, ofsEnd, SEEK_CUR);
}
